# facial landmark 3
# detect facial landmarks using dlib

import cv2
import dlib
from imutils import face_utils
import imutils

# load image and ->gray_img
test_face = cv2.imread("03.jpg")
# 图片尺寸太小，面部特征点识别时会有一定程度检测不到人脸，太大又会导致显示不全从而导致检测不到人脸
test_face = imutils.resize(test_face, width=500)
gray = cv2.cvtColor(test_face, cv2.COLOR_BGR2GRAY)

# face detect
detector = dlib.get_frontal_face_detector()
rects = detector(gray, 1)
print(rects)

# detect facial landmarks
p = "shape_predictor_68_face_landmarks.dat"
predictor = dlib.shape_predictor(p)

# 使用线条绘制面部特征点形状，以连接绘制脸部的不同部分的轮廓(例如鼻子、眼睛等
# 定义不同特征点取值切片
jawline_points = list(range(0, 17))  # 下巴
right_eyerow_points = list(range(17, 22))  # 右眉毛
left_eyerow_points = list(range(22, 27))  # 左眉毛
nose_bridge_points = list(range(27, 31))  # 鼻梁
lower_nose_points = list(range(31, 36))  # 下鼻
right_eye_points = list(range(36, 42))  # 右眼
left_eye_points = list(range(42, 48))  # 左眼
mouth_outline_points = list(range(48, 61))  # 嘴巴轮廓
mouth_inner_point = list(range(61, 68))  # 口内
all_points = list(range(0, 68))


# 使用线条绘制面部特征点
def draw_shape_lines_all(np_shape):
    draw_shape_lines_range(np_shape, jawline_points)
    draw_shape_lines_range(np_shape, right_eye_points)
    draw_shape_lines_range(np_shape, left_eye_points)


# 连接不同的点来绘制曲线形状
def draw_shape_lines_range(np_shape, range_points):
    for (x, y) in np_shape[range_points]:
        cv2.circle(test_face, (x, y), 2, (255, 255, 0), 1)


# enumerate()方法用于将一个可遍历的数据对象(列表、元组、字典)组合
# 为一个索引序列，同时列出 数据下标 和 数据 ，一般用在for循环中
for (i, rect) in enumerate(rects):
    # 标记人脸中的68个landmark点
    shape = predictor(gray, rect)
    # shape转换成68个坐标点矩阵
    shape = face_utils.shape_to_np(shape)

    # 返回人脸框的左上角坐标和矩形框的尺寸
    (x, y, w, h) = face_utils.rect_to_bb(rect)
    cv2.rectangle(test_face, (x, y), (x + w, y + h), (255, 0, 0), 2)
    cv2.putText(test_face, "face #{}".format(i + 1), (x - 10, y - 10),
                cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 1)

    """
    landmarksNum = 0
    jawline_points = list(range(0, 17))
    for (x, y) in shape[jawline_points]:
        cv2.circle(test_face, (x, y), 2, (0, 0, 255), -1)
        landmarksNum += 1
    print(landmarksNum)
    """
    draw_shape_lines_all(shape)
    # print(shape)

# 函数调用
# draw_shape_lines_all(shape, test_face)
cv2.imshow("landmarks detection using dlib", test_face)
cv2.waitKey(0)
